package fr.neyb.bernouilli.common.math.prime;

import java.util.ArrayList;

import fr.neyb.bernouilli.common.exception.MathLimitExceededException;

public class PrimeGenerator2 {

	private static class Prime {
		private final long primeValue;
		private long rest = 0;

		public Prime(long value) {
			this.primeValue = value;
		}

		public boolean incr() {
			return incr(1);
		}

		public boolean incr(long val) {
			rest += val;
			if (rest >= primeValue) {
				rest %= primeValue;
				return true;
			} else {
				return false;
			}
		}
	}

//	private static class Decalator {
//		private long fromIndex;
//		private long decaleValue;
//
//		public Decalator(int fromIndex, int decaleValue) {
//			this.fromIndex = fromIndex;
//			this.decaleValue = decaleValue;
//		}
//		
//		public void decale(){
//			++fromIndex;
//		}
//
//		public long incr(Decalator dec) {
//			return decaleValue += dec.decaleValue;
//		}
//	}
//
//	private static class Decalators{
//		private ArrayList<Decalator> decalators = new ArrayList<>();
//		
//		public decale
//		
//	}
	
	private final ArrayList<Prime> primesFound = new ArrayList<>();
	private int position =0;
//	private final Decalators dec = new Decalators();

	public int nbPrimes() {
		return primesFound.size();
	}

	public long getNextPrime() {

		switch (position) {
		case 0:
			primesFound.add(new Prime(2));
			return 2;
		case 1:
			primesFound.add(new Prime(3));
			return 3;
		}

		long curr = primesFound.get(position - 1).primeValue + 2;

		int incr;
		if (curr % 3 == 0) {
			curr += 2;
			incr = 4;
		} else {
			incr = 2;
		}

		long[] prevPrimes = calculatedPrimes();

		for (;; curr += (incr = 6 - incr)) {
			boolean prime = true;

			if (curr > Integer.MAX_VALUE)
				throw new MathLimitExceededException();
			int isqrt = (int) Math.ceil(Math.sqrt((int) curr));
			// TODO extends to long (means impl sqrt for long)
			// int isqrt = MyMath.i_sqrt(curr);

			for (long currPrime : prevPrimes) {
				if (currPrime > isqrt)
					break;

				if (curr % currPrime == 0) {
					prime = false;
					break;
				}
			}

			if (prime) {
				primesFound.put(curr);
				return curr;
			}
		}
	}
}
